/*
    WiiCade Wii Remote API v2.0 
    Copyright (C) 2007 Jerason Banes

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.
    
    It is understood that no reaonable library system exists for Flash
    programs. To that end, this library is considered to be in library
    form when distributed as a source code package for linking to 
    Flash and Actionscript programs. Similarly, static linking of the
    library is understood to be the preferred form of distributing
    the library in binary form.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

import mx.events.EventDispatcher;

import com.wiicade.*;

/**
 * This class is the entry point into the functionality provided by
 * the Wii console. 
 **/
class com.wiicade.Wii
{
    /** @private */
    static public var COMMAND_BUTTONS:Number  = 0x01;
    static public var COMMAND_TWIST:Number    = 0x05;
    static public var COMMAND_DISTANCE:Number = 0x09;
    static public var COMMAND_FLAGS:Number    = 0x0D;
    static public var COMMAND_ATTACH:Number   = 0x0E;
    static public var COMMAND_CURSORX:Number  = 0x12;
    static public var COMMAND_CURSORY:Number  = 0x16;
    
    private var lc;
    private var remotes = new Array();
    private var activated = new Array();
    private var primary = 0;
    private var virtualized = false;
    private var wii = true;
    
    private var keyboard:KeyboardController;
    
    static private var instance:Wii; //= new Wii();

    private function Wii()
    {
        if(!_global.Wii) _global.Wii = this;
        else return;

        wii = (System.capabilities.os == "Nintendo Wii");
        
        //Initialize child classes
        WiiRemote.init();
        KeyboardController.init();
        Browser.init();

        for(var i=0; i<4; i++)
        {
            this.remotes[i] = new WiiRemote(i);
        }
      
        if(!Wii.isWii()) keyboard = new KeyboardController(wiicommand);

        lc = new LocalConnection();
        lc.connect("wii");
        lc.wiicommand = function(packet) {_global.Wii.wiicommand(packet);};

        //Activate the Javascript subsystem
        if(Wii.isWii()) getURL("javascript:initializeWiiCadeAPI(20, "+Stage.width+", "+Stage.height+");");
    }
    
    static private function getInstance()
    {
        if(!_global.Wii) instance = new Wii();
        
        return _global.Wii;
    }
    
    static private function init()
    {
        _global.Wii = null;
        instance = new Wii();
    }

    /**
     * Return true if the current system is a Nintendo Wii, false if it is
     * any other platform.
     **/
    static public function isWii():Boolean
    {
        var wii = getInstance();
        
        return (wii.wii || wii.virtualized);
    }

    private function wiicommand(packet:Number):Void
    {
        var wii = getInstance();
        var command = (0xFFFF0000 & packet) >> 16;
        var data = (packet & 0xFFFF);

        if(command < 0x05) wii.remotes[command-1].buttonsUpdated(data);
        else if(command < 0x09) wii.remotes[command-0x05].twistUpdated(data);
        else if(command < 0x0D) wii.remotes[command-0x09].distanceUpdated(data);
        else if(command == 0x0D) parseFlags(data); //Handle Flags
        else if(command < 0x12) parseAttachment(data, command-0x0E); //Handle External Devices
        else if(command < 0x16) wii.remotes[command-0x12].cursorXUpdated(data);
        else if(command < 0x20) wii.remotes[command-0x16].cursorYUpdated(data);
    }
    
    private function parseFlags(flags)
    {
        var oldprimary = primary;
        var remote;
        var connected;
        var mask = (0x01 << 3);
        
        primary = flags & 0x03;
        
        if(primary != oldprimary)
        {
            getRemote(oldprimary).updatePrimary(false);
            getRemote(primary).updatePrimary(true);
        }
        
        virtualized = (((0x01 << 2) & mask) > 0);
        
        for(var i=0; i<4; i++)
        {
            remote = getRemote(i);
            connected = ((mask & flags) > 0); 
            
            if(remote.isConnected() != connected) remote.connectedUpdated(connected);
            
            mask <<= 1;
        }
    }
    
    private function parseAttachment(data, remote)
    {
        var wiiremote = getRemote(remote);
        var attachment = wiiremote.getAttachment();

        var x;
        var y;
        
        if((data & 0x100) == 0)
        {
            //Nunchuk
            if(!(attachment instanceof Nunchuk)) 
            {
                attachment = new Nunchuk(wiiremote);
                wiiremote.updateAttachment(attachment);
            }
            
            attachment.updateButtons((data & 0x03));
            
            x = ((data & 0x1C) >>> 2);
            y = ((data & 0xE0) >>> 5);
            
            if((x & 0x04) > 0) x |= 0xFFF8;
            if((y & 0x04) > 0) y |= 0xFFF8;
            
            x = Math.floor((x * 128) / 3);
            y = Math.floor((y * 128) / 3);
            
            attachment.updateStick(x, y);
        }
        else
        {
            //Classic Controller
        }
    }

    /**
     * The Wii can support up to four Wii Remote controllers. These controllers
     * are numbered 0, 1, 2, and 3. Call this function with one of those four
     * values to retrieve an object containing information about the specific
     * remote. 
     *
     * @param identity The id of the Wii Remote you wish to query.
     * @return A WiiRemote object containing information about the remote.
     **/
    static public function getRemote(identity:Number):WiiRemote
    {
        var wii = getInstance();
        
        if(!wii.activated[identity] && wii.isWii())
        {
            getURL("javascript:activateWiiRemoteFeature("+identity+", null, true);");
            wii.activated[identity] = true;
        }
        
        return wii.remotes[identity];
    }

    /**
     * Out of the four remotes, only one remote is allowed to directly interact 
     * with the webpage. This remote is the "Primary" remote. While this remote
     * is usually the first remote (id 0), it is possible for other remotes to
     * be the primary remote if the first remote is turned off.<br>
     * <br>
     * Use this function to retrieve a WiiRemote object containing information
     * about the primary remote. This function is useful in single-player games 
     * where the user expects the remote that's turned on to be able to interact
     * with the Flash movie. <br>
     * <br>
     * Authors upgrading from the earlier WiiCade API should use 
     * Wii.getPrimaryRemote() in place of calling functions on the WiiMote
     * object.
     *
     * @returns The WiiRemote object for the current remote.
     **/
    static public function getPrimaryRemote():WiiRemote
    {
        var wii = getInstance();
        
        return wii.remotes[wii.primary];
    }
}
